iT邦幫忙

2024 iThome 鐵人賽

DAY 8
1
Modern Web

一些讓你看來很強的 ORM - prisma系列 第 8

Day08. 一些讓你看來很強的 ORM - prisma (schema)下

  • 分享至 

  • xImage
  •  

今天要來補充 schema 的進階用法,延續昨天在 prisma 中使用 DB adapterschema 根據不同的 connect pool 去執行 DB 的內容,但你會發現一件事情,那就是每當你要切換不同的 schema 都要更改 DATABASE_URL.env

甚至你的 adapter 也需要去調整

const adapter = new PrismaPg(pool, {
  schema: 'test'
})

但如果今天專案一大起來,你有多個 schema ,同時你需要共用不同 schematable 去關聯資料的話,顯然昨日單個 schema 這樣的切換是無法做到的,那今天內容就來教大家如何在 prisma 中使用多個 schema 然後關聯不同 schematable~

Setting

prisma 中要使用 multiple database schema 必須要設定 preview featuregenerator client 這邊,跟昨天的 driverAdapters 一樣

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["driverAdapters", "multiSchema"]
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

Add schema

我們除了可以在 DB 自己新增 schema 外,也可以透過 schema.prisma 去幫我們 generate ,只需要在 datasource db 中去指定哪些 schema 需要被使用

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["driverAdapters", "multiSchema"]
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
  schemas  = ["base", "transactional"]
}

同時你的 DATABASE_URL 也不需要去加上 schemaparameter ,完全不需要更動

//.env
DATABASE_URL="postgresql://root:****@***.***.zeabur.com:***/zeabur"

這時候你會發現當擬定好共用的 schema 後,假設你要新增一個 model ,此時 prisma 會跳一個 error 說他不知道這個 model 屬於哪個 schema 的範疇
https://ithelp.ithome.com.tw/upload/images/20240922/20145677RGsZhsH3pq.png

所以每當新建一個 model 都會需要用 @@schema 去告訴 prisma 這個 model 屬於哪個 schema 使用,然後除了 modelenum 也可以指定 schema ~

model User {
  id     Int     @id
  orders Order[]

  @@schema("base")
}

model Order {
  id      Int  @id
  user    User @relation(fields: [id], references: [id])
  user_id Int

  @@schema("transactional")
}

enum Size {
  Small
  Medium
  Large

  @@schema("transactional")
}

執行完後我們就把 model migrateDB

>npx prisma migrate dev --name init 

然後當你查看現在的 schema 時,你會發現已經成功加進去了~

>zeabur=# \dn;
          List of schemas
     Name      |       Owner
---------------+-------------------
 base          | root
 public        | pg_database_owner
 transactional | root
(3 rows)

那因為預設的 schema 是在 public 所以會沒有 table 是正常的

>zeabur=# \dt;
              List of relations
 Schema |        Name        | Type  | Owner
--------+--------------------+-------+-------
 public | _prisma_migrations | table | root
(1 row)

之後切換 schema 查看 table,你會發現 prisma 已經成功幫我們區分不同的 table 到各自的 schema 中了~

>zeabur=# SET SEARCH_PATH=base;
SET
>zeabur=# \dt;
        List of relations
 Schema |  Name   | Type  | Owner
--------+---------+-------+-------
 base   | User    | table | root
(3 rows)

Same Table Difference Schema

另外有一種情形是,如果你需要不同的 schema 有相同的 table name 也是可行的喔,你只需要改變一下 model name ,然後 @@maptable name 以及加上 @@schema 就可以

model BaseConfig {
   id     Int     @id @default(autoincrement())
  name   String

  @@map("config")
  @@schema("base")
}

model TransactionalConfig {
   id     Int     @id @default(autoincrement())
  name   String

  @@map("config")
  @@schema("transactional")
}

之後我們 migrateDB

>npx prisma migrate dev --name add_profile

你會發現不管是 base Schema 或是 transactional Schema 都有 config 這個 table

>zeabur=# SET SEARCH_PATH=base;
SET
>zeabur=# \dt;
        List of relations
 Schema |  Name   | Type  | Owner
--------+---------+-------+-------
 base   | User    | table | root
 base   | config  | table | root
>zeabur=# SET SEARCH_PATH=transactional;
SET
>zeabur=# \dt;
           List of relations
    Schema     |  Name  | Type  | Owner
---------------+--------+-------+-------
 transactional | Order  | table | root
 transactional | config | table | root
(2 rows)

最後我們在 studio 加上 dataBaseConfigTransactionalConfig
https://ithelp.ithome.com.tw/upload/images/20240922/20145677Fim5rSs4gX.png

然後執行 index.ts

>tsx watch index.ts     
//index.ts
import { Pool } from 'pg'
import { PrismaPg } from '@prisma/adapter-pg'
import { PrismaClient } from '@prisma/client'

const connectionString = `${process.env.DATABASE_URL}`

const pool = new Pool({ connectionString })
const adapter = new PrismaPg(pool)
const prisma = new PrismaClient({ adapter })
const main = async () => {
  const data = await prisma.baseConfig.findMany({})
  const data2 = await prisma.transactionalConfig.findMany({})
  console.log(data, data2)
}

你會發現我們成功拿到兩個 schema 中的資料了~

[ { id: 1, name: 'baseConfig' } ] [ { id: 1, name: 'transactionalConfig' } ]

甚至因為 schema.prismapreviewFeatures ,所以 adapterschema 就可以直接拿掉了~

// before
const adapter = new PrismaPg(pool, {
  schema:'test'
})

// after
const adapter = new PrismaPg(pool)

甚至用了 @@schema 也是可以做關聯資料的~

model User {
  id      Int      @id
  orders  Order[]
  profile Profile?

  @@schema("base")
}

model Profile {
  id     Int    @id @default(autoincrement())
  bio    String
  user   User   @relation(fields: [userId], references: [id])
  userId Int    @unique

  @@schema("base")
}

model Order {
  id      Int  @id
  user    User @relation(fields: [id], references: [id])
  user_id Int

  @@schema("transactional")
}

enum Size {
  Small
  Medium
  Large

  @@schema("transactional")
}

query data 也跟以往的方式一樣沒變化~

const orders = await prisma.order.findMany({
  where: {
    user: {
      id: 1,
    },
  },
})

以上就是所有 schema 的內容,總共花了三天來介紹這個,希望大家可以學到,謝謝大家耐心地閱讀到這邊~

大家如果有問題可以來小弟的群組討論~

✅ 前端社群 :
https://lihi3.cc/kBe0Y


上一篇
Day07. 一些讓你看來很強的 ORM - prisma (schema)中
下一篇
Day09. 一些讓你看來很強的 ORM - prisma (model)
系列文
一些讓你看來很強的 ORM - prisma30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言